#Liang Wang
#
import zmq
import time
import uuid
import json
import zlib,sys
import logging
import marshal
import cPickle
import types
import copy
sys.path.append("./")
from utils import *

USER=0
GUARD=1
DEFAULT=0


logging.basicConfig(format="[%(asctime)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S",level=logging.DEBUG)

class GuardAttr(object):
	"""docstring for GuardAttr"""
	def __init__(self,_id,reginfo):
		self.id=_id
		self.policy=[]
		self.group=0
		self.app=[]
		self.nf={}
		self.mac={}
		self.ip={}
		self.nm={}
		self.bc={}
		self.info_len=0
		self.load_info(reginfo)
	
	def load_info(self,info):
		count=0
		for k in info:
			self.nf[count]=k
			i=info[k]
			self.mac[count]=i['mac']
			self.ip[count]=i['ip']
			self.nm[count]=i['nm']
			self.bc[count]=i['bc']
			count=count+1
		self.info_len=count

class Admin(object):
	"""docstring for Admin"""
	def __init__(self, usr):
		self.id=usr
		self.tb_guards={}
		self.tb_connection={}
		self.tb_group={}
		self.tb_group[DEFAULT]=[]
		self.attr_set=GuardAttr(0,{}).__dict__

	def update(self,guards,connection):
		self.tb_guards=copy.deepcopy(guards)
		self.tb_connection=copy.deepcopy(connection)

class AdminView(object):
	"""docstring for AdminManger"""
	def __init__(self):
		self.admin_pool={}
		self.admin_pool["root"]=Admin("root")
		self.usr=self.admin_pool["root"]

	def sync_root(self,guards,connection):
		self.admin_pool["root"].update(guards,connection)

	def set_user(self,usrid):
		if usrid in self.admin_pool:
			self.usr=self.admin_pool[usrid]
			return True
		else:
			return False
	def get_user(self,usrid):
		return self.admin_pool[usrid]
	def create_user(self,usrid):
		self.admin_pool[usrid]=Admin(usrid)

	def assign_guard(self,src_admin,dst_admin,guards):
		src_admin=self.get_user(src_admin)
		if dst_admin not in self.admin_pool:
			self.create_user(dst_admin)
		dst_admin=self.get_user(dst_admin)
		legal_guards=src_admin.tb_guards.keys()
		target_guards=guards
		if target_guards==DEFAULT: #assign all guards
			target_guards=legal_guards
		else:
			if set(target_guards)|set(legal_guards)!=set(legal_guards):
				return False
		for g in target_guards:
			self.admin_pool[dst_admin.id].tb_guards[g]=copy.deepcopy(self.admin_pool[src_admin.id].tb_guards[g])
		return True
		

	def assign_apps(self,src_admin,dst_admin,apps):
		if dst_admin not in self.admin_pool:
			self.assign_guard(src_admin,dst_admin,DEFAULT)
		src_admin=self.get_user(src_admin)
		dst_admin=self.get_user(dst_admin)
		legal_apps=[]
		legal_guards=dst_admin.tb_guards.keys()
		for g in legal_guards:
			legal_apps+=dst_admin.tb_guards[g].app

		if set(apps)|set(legal_apps) != set(legal_apps):
			return False
		for g in legal_guards:
			self.admin_pool[dst_admin.id].tb_guards[g].app=[]
			for ap in apps:
				if ap in self.admin_pool[src_admin.id].tb_guards[g].app:
					self.admin_pool[dst_admin.id].tb_guards[g].app.append(ap)
		return True

	def op_group_new(self,name):
		if name in self.usr.tb_group:
			return False
		self.usr.tb_group[name]=[]
		return True

	def op_group_del(self,name):
		if name in self.usr.tb_group:
			tmp=self.usr.tb_group.pop(name)
			for t in tmp:
				self.usr.tb_guards[t].group=DEFAULT
				self.usr.tb_group[DEFAULT].append(t)
			return tmp
		else:
			return False

	def op_group_add_member(self,name,target):
		if not target:
			return False
		if name not in self.usr.tb_group:
			return False
		else:
			if self.usr.tb_guards[target].group != DEFAULT:
				return False
			else:
				self.usr.tb_group[DEFAULT].remove(target)
				self.usr.tb_group[name].append(target)
				self.usr.tb_guards[target].group=name
				return True		

	def op_group_rm_member(self,target):
		if target not in self.usr.tb_guards:
			return False
		name=self.usr.tb_guards[target].group
		if target not in self.usr.tb_group[name]:
			return False
		else:
			self.usr.tb_group[name].remove(target)
			self.usr.tb_group[DEFAULT].append(target)
			self.usr.tb_guards[target].group=DEFAULT
			return True

	def op_group_list_members(self,name):
		return self.usr.tb_group[name]

	def op_guard_list_alive(self):
		self.root=self.admin_pool["root"]
		return [v for v in self.usr.tb_guards.keys() if self.root.tb_connection[v]==1]

	def op_guard_list_all(self):
		return self.usr.tb_guards.keys()

	def op_guard_info(self,tid):
		if tid in self.usr.tb_guards:
			guard=self.usr.tb_guards[tid]
			return guard.__dict__
		return False


		
		
class MessageHandler(object):
	"""docstring for MessageHandler"""
	def __init__(self):
		
		self.tb_guards={}
		self.tb_connection={}
		self.tb_group={}
		self.tb_group[0]=[]
		self.e=ErrLog()
		self.view=AdminView()
		self.attr_set=GuardAttr(0,{}).__dict__


	def guard_connect(self,tid,content):
		self.tb_guards[tid]=content
		self.tb_connection[tid]=1
		self.view.sync_root(self.tb_guards, self.tb_connection)
		self.view.admin_pool["root"].tb_group[DEFAULT].append(tid)

	def guard_close(self,tid):
		self.tb_connection[tid]=0
		self.view.sync_root(self.tb_guards, self.tb_connection)
		

	def op_get_targets(self,appid,groupid=None,guardid=None):
		targets=[]
		for t in self.usr.tb_guards.items():
			g=t[1]
			f1,f2,f3=True,True,True
			f1=(appid in g.app)
			if groupid:
				f2=(groupid==g.group)
			if guardid:
				f3=(guardid==g.id)
			print f1,f2,f3
			if f1&f2&f3:
				targets.append(g.id)

		return targets



	def op_policy_add(self,tid,policy):
		self.usr.guard[tid].policy.append(policy)
		return True

	def op_policy_get(self,tid):
		return self.usr.guard[tid].policy

	def event_app_register(self,msg,cflag=False):
		logging.info("A new application register to guard %s: %s",msg[MSG_SENDER],msg)
		self.tb_guards[msg[MSG_SENDER]].app.append(msg[MSG_BODY])
		self.view.sync_root(self.tb_guards, self.tb_connection)
		return GUARD,pack_msg(msg)

	def event_guard_register(self,msg,cflag=False):
		src_guard=msg[MSG_SENDER]
		if src_guard=="None":
			nid=generate_id()
			while nid in self.tb_guards:
				nid=generate_id()

		self.guard_connect(nid,GuardAttr(nid,msg[MSG_BODY]))
		print self.view.get_user("root")
		logging.info("Register guard %s,%s",nid,self.tb_guards[nid].__dict__)
		msg={}
		msg[MSG_TYPE]=TYPE_REP_REGISTER
		msg[MSG_SENDER]=nid
		return GUARD,pack_msg(msg,cflag)


	def event_group_new(self,msg,cflag=False):
		logging.info("Get GROUP_BUILD request from user %s: %s",msg[MSG_SENDER],msg)
		group_name=msg[MSG_BODY][MSG_TARGET]
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		if not self.view.op_group_new(group_name):
			self.e.append("Group %s already exist"%(group_name))
		else:
			for t in msg[MSG_BODY]["member"]:
				if not t:
					continue
				if not self.view.op_group_add_member(group_name,t):
					self.e.append("%s fail to add to new group"%(t))
	
		if self.e.flag:
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		else:
			msg[MSG_TYPE]=TYEP_REP_OPERS_ERR
			msg[MSG_BODY][MSG_FAIL]=str(self.e)
		self.e.clear()
		return USER,pack_msg(msg,cflag)


	def event_group_del(self,msg,cflag=False):
		logging.info("Get GROUP_DEL request from user %s: %s",msg[MSG_SENDER],msg)
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		src_group=msg[MSG_BODY][MSG_FROM]
		dst_group=msg[MSG_BODY][MSG_TO]
		if not dst_group:
			dst_group=DEFAULT
		tmp=self.view.op_group_del(src_group)
		if not tmp:
			self.e.append("Fail to delete group %s"%(src_group))
		else:
			for t in tmp:
				if not self.view.op_group_add_member(dst_group,t):
	
					self.e.append("Fail to add guard %s to group %s"%(t,dst_group))
		if self.e.flag:
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		else:
			msg[MSG_TYPE]=TYEP_REP_OPERS_ERR
			msg[MSG_BODY][MSG_FAIL]=str(self.e)
		self.e.clear()
		return USER,pack_msg(msg,cflag)

	def event_group_add(self,msg,cflag=False):
		logging.info("Get GROUP_ADD request from user %s: %s",msg[MSG_SENDER],msg)
		dst_group=msg[MSG_BODY][MSG_TARGET]
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		for t in msg[MSG_BODY]["member"]:
			if not self.view.op_group_add_member(dst_group,t):
				self.e.append("Fail to add guard %s to group %s"%(t,dst_group))
		if self.e.flag:
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		else:
			msg[MSG_TYPE]=TYEP_REP_OPERS_ERR
			msg[MSG_BODY][MSG_FAIL]=str(self.e)
		self.e.clear()
		return USER,pack_msg(msg,cflag)

	def event_group_move(self,msg,cflag=False):
		logging.info("Get GROUP_MOVE request from user %s: %s",msg[MSG_SENDER],msg)
		targets=msg[MSG_BODY][MSG_TARGET]
		dst_group=msg[MSG_BODY]["member"]
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		for t in targets:
			if self.view.op_group_rm_member(t):
				if not self.view.op_group_add_member(dst_group,t):
					self.e.append("Fail to add guard %s to group %s"%(t,dst_group))
			else:
				self.e.append("Fail to remove guard %s"%(t))
		if self.e.flag:
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		else:
			msg[MSG_TYPE]=TYEP_REP_OPERS_ERR
			msg[MSG_BODY][MSG_FAIL]=str(self.e)
		self.e.clear()
		return USER,pack_msg(msg,cflag)

	def event_group_list(self,msg,cflag=False):
		logging.info("Get GROUP_LIST request from user %s: %s",msg[MSG_SENDER],msg)
		msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		msg[MSG_BODY]=self.view.usr.tb_group
		return USER,pack_msg(msg,cflag)

	def event_guard_list(self,msg,cflag=False):
		logging.info("Get GUARD_LIST request from user %s: %s",msg[MSG_SENDER],msg)
		msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		tmp={}
		target=msg[MSG_BODY][MSG_TARGET]
		if target=="ALL":
			for v in self.view.usr.tb_guards:
				tmp[v]=self.view.op_guard_info(v)
		else:
			for v in self.view.usr.tb_group[target]:
				tmp[v]=self.view.op_guard_info(v)
		msg[MSG_BODY]=tmp
		return USER,pack_msg(msg,cflag)

	def event_guard_info(self,msg,cflag=False):
		msg[MSG_TYPE]=TYEP_REP_OPERS_OK
		usr=msg[MSG_SENDER]
		if not self.view.set_user(usr):
			return USER,error_msg()
		target=msg[MSG_BODY][MSG_TARGET]
		msg[MSG_BODY]=self.view.op_guard_info(target)
		return USER,pack_msg(msg,cflag)

		

class Controller(MessageHandler):
	"""docstring for Controller"""
	def __init__(self):
		##state table
		MessageHandler.__init__(self)
		##init important variables
		self.context=zmq.Context()
		self.guardend=self.context.socket(zmq.ROUTER)
		self.userend=self.context.socket(zmq.DEALER)
		self.poller = zmq.Poller()
		self.ctr_name=""
		self.ctr_code=""
		self.ctr_args=""


		###init actions
		self.bind()
		self.run()
		pass

	def bind(self):
		self.guardend.bind("tcp://*:5555")
		self.userend.bind("tcp://*:5556")
		self.poller.register(self.guardend, zmq.POLLIN)
		self.poller.register(self.userend, zmq.POLLIN)
		logging.info("Init controller...")

	def run(self):
		logging.info("Controller is running...")
		while 1:
			sockets = dict(self.poller.poll(1))
			if self.guardend in sockets:
				if sockets[self.guardend] == zmq.POLLIN:
					_id = self.guardend.recv()
					msg = eval(self.guardend.recv())
					to,msg=self.msg_handler(msg)
					if to==GUARD:
						self.guardend.send(_id, zmq.SNDMORE)
						self.guardend.send(msg)
					else:
						pass
			if self.userend in sockets:
				if sockets[self.userend] == zmq.POLLIN:
					msg=self.userend.recv()
					try:
						msg = eval(msg)
					except:
						msg=cPickle.loads(msg)
					to,msg=self.msg_handler(msg)
					if to==USER:
						self.userend.send(msg)
					else:
						for _id in msg[0]:
							self.guardend.send(_id, zmq.SNDMORE)
							self.guardend.send(msg[1])
						pass


	def msg_handler(self,msg):
		msg_type=msg[MSG_TYPE]
		if msg_type==TYEP_REGISTER:
			return  self.event_guard_register(msg)

		if msg_type==TYPE_GROUP_BUILD:
			return self.event_group_new(msg)

		if msg_type==TYPE_GROUP_ADD:
			return self.event_group_add(msg)

		if msg_type==TYPE_GROUP_DEL:
			return self.event_group_del(msg)

		if msg_type==TYPE_GROUP_MOVE:
			return self.event_group_move(msg)

		if msg_type==TYPE_GROUP_LIST:
			return self.event_group_list(msg)

		if msg_type==TYPE_GUARD_LIST:
			return self.event_guard_list(msg)

		if msg_type==TYPE_GUARD_GET:
			return self.event_guard_info(msg)

		####################
		if msg_type==TYPE_APP_ADD:
			return self.event_app_register(msg)

				
		if msg_type==TYPE_UPDATE_CONTROL:
			self.ctr_name=msg[MSG_BODY].keys()[0]
			self.ctr_code=marshal.loads(msg[MSG_BODY][self.ctr_name]["code"])
			self.ctr_args=msg[MSG_BODY][self.ctr_name]["args"]
			msg={}
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
			msg[MSG_BODY]=self.tb_group
			return USER,pack_msg(msg)
			pass
			
		if msg_type==TYPE_MISSPOLICY:
			#build application here
			msg[MSG_TYPE]=TYPE_REP_MISSPOLICY
			pass





		if msg_type==TYPE_GUARD_DEBUG:
			logging.info("Get DEBUG request from guard %s: %s",msg[MSG_SENDER],msg)
			msg[MSG_TYPE]=TYPE_REP_GUARD_DEBUG
			return GUARD,json.dumps(msg)

		if msg_type==TYPE_USR_DEBUG:
			usr=msg[MSG_SENDER]
			print self.view.assign_apps("root","123",["app0"])
			print [(v,self.view.get_user("123").tb_guards[v].app) for v in self.view.get_user("123").tb_guards.keys()]
			print [(v,self.view.get_user("root").tb_guards[v].app) for v in self.view.get_user("root").tb_guards.keys()]
			print self.view.assign_guard("root","123",self.tb_guards)
			print [(v,self.view.get_user("123").tb_guards[v].app) for v in self.view.get_user("123").tb_guards.keys()]
			print [(v,self.view.get_user("root").tb_guards[v].app) for v in self.view.get_user("root").tb_guards.keys()]		
			

			return USER,pack_msg(msg)




			"""
			logging.info("Get DEBUG request from user %s: %s",msg[MSG_SENDER],msg)
			msg[MSG_TYPE]=TYPE_REP_USR_DEBUG
			msg[MSG_BODY]="DEBUG_GROUP"
			print self.ctr_args
			func=types.FunctionType(self.ctr_code, globals(), 'func', (self.ctr_name,msg))
			func()
			msg={}
			msg[MSG_TYPE]=TYEP_REP_OPERS_OK
			msg[MSG_BODY]=self.tb_group
			return USER,pack_msg(msg)
			#return self.even_policy_put(msg)
			
			targets=self.tb_group[DEFAULT]
			msg[0]=targets
			msg[1]=json.dumps(msg)
			return GUARD,msg
			"""


if __name__ == '__main__':
	c=Controller()

